package com.yangmy.cobweb.application.admin.controller;

import com.yangmy.cobweb.application.admin.api.let.DockerApi;
import com.yangmy.cobweb.application.admin.domain.dto.Node;
import com.yangmy.cobweb.application.admin.domain.dto.NodeDockerContainer;
import com.yangmy.cobweb.application.admin.utils.ClusterContext;
import com.yangmy.cobweb.application.admin.websocket.DockerLogsEndpoint;
import com.yangmy.cobweb.common.core.domain.R;
import com.yangmy.cobweb.common.core.utils.rest.RestUtils;
import com.yangmy.cobweb.common.docker.domain.DockerContainer;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.websocket.Session;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

/**
 * @author YangMingYang
 * @since 2022/10/3
 */
@Slf4j
@Validated
@Api(tags = "容器相关接口")
@RestController
@RequestMapping("/container")
public class ContainerController {

    @Resource
    private DockerApi dockerApi;
    @Resource
    private ClusterContext clusterContext;

    @ApiOperation("查询集群中所有容器")
    @GetMapping("/listClusterContainer")
    public R<List<NodeDockerContainer>> listClusterContainer(){
        List<NodeDockerContainer> resList=new LinkedList<>();
        List<Node> nodeList=clusterContext.list();
        for (Node node : nodeList) {
            RestUtils.setBaseURL(node.getBaseURL());
            R<List<DockerContainer>> r=dockerApi.listContainer();
            if(r.getCode()==200){
                List<DockerContainer> list=r.getData();
                for (DockerContainer dockerContainer : list) {
                    NodeDockerContainer nodeDockerContainer=new NodeDockerContainer();
                    BeanUtils.copyProperties(dockerContainer,nodeDockerContainer);
                    nodeDockerContainer.setIp(node.getIp());
                    resList.add(nodeDockerContainer);
                }
            }
        }
        //按时间排序
//        resList.stream().sorted(()->{
//
//        });
        return R.success(resList);
    }

    @ApiOperation("查询指定节点所有容器")
    @GetMapping("/listContainer")
    public R<List<DockerContainer>> listContainer(@RequestParam String ip){
        RestUtils.setBaseURL(clusterContext.getNodeBaseURL(ip));
        return dockerApi.listContainer();
    }

    @ApiOperation("在指定节点上创建容器并运行")
    @PostMapping("/runContainer")
    public R<Void> runContainer(@RequestParam String ip,
                                  @RequestParam("containerName") String containerName,
                                  @RequestParam("imageName") String imageName,
                                  @RequestParam("tag") String tag,
                                  @RequestParam(value = "options",required = false) String options){
        RestUtils.setBaseURL(clusterContext.getNodeBaseURL(ip));
        return dockerApi.runContainer(containerName,imageName,tag,options);
    }

    @ApiOperation("启动容器")
    @PutMapping("/startContainer")
    public R<Void> startContainer(@RequestParam String ip,
                                    @RequestParam("containerId") String containerId){
        RestUtils.setBaseURL(clusterContext.getNodeBaseURL(ip));
        return dockerApi.startContainer(containerId);
    }

    @ApiOperation("停止容器")
    @PutMapping("/stopContainer")
    public R<Void> stopContainer(@RequestParam String ip,
                                   @RequestParam("containerId") String containerId){
        RestUtils.setBaseURL(clusterContext.getNodeBaseURL(ip));
        return dockerApi.stopContainer(containerId);
    }

    @ApiOperation("删除容器")
    @DeleteMapping("/deleteContainer")
    public R<Void> deleteContainer(@RequestParam String ip,
                                     @RequestParam("containerId") String containerId){
        RestUtils.setBaseURL(clusterContext.getNodeBaseURL(ip));
        return dockerApi.deleteContainer(containerId);
    }

    @ApiOperation("推送日志")
    @PostMapping("/sendLog")
    public R<Void> sendLog(@RequestParam String sessionId,
                             @RequestParam String line){
        Map<Session,String> sessionMap= DockerLogsEndpoint.sessionMap;
        for (Session session : sessionMap.keySet()) {
            if(session.getId().equals(sessionId)){
                session.getAsyncRemote().sendText(line);
            }
        }
        return R.success();
    }

}
/*
Options:
      --add-host list                  添加一个自定义主机到ip的映射(host:ip) Add a custom host-to-IP mapping (host:ip)
  -a, --attach list                    附加到STDIN, STDOUT或STDERR Attach to STDIN, STDOUT or STDERR
      --blkio-weight uint16            块IO(相对权重)，在10和1000之间，或0禁用 Block IO (relative weight), between 10 and 1000, or 0 to disable
                                       (default 0)
      --blkio-weight-device list       块IO权重(相对设备权重)(default []) Block IO weight (relative device weight) (default [])
      --cap-add list                   添加Linux功能 Add Linux capabilities
      --cap-drop list                  Linux的能力下降 Drop Linux capabilities
      --cgroup-parent string           容器的可选父cgroup Optional parent cgroup for the container
      --cgroupns string                要使用的Cgroup命名空间(主机|私有)'host':在Docker主机的cgroup命名空间中运行容器'private':
                                        在它自己的私有cgroup命名空间中运行容器":使用由守护进程上的default-cgroupns-mode选项配置的cgroup命名空间(默认)
                                        Cgroup namespace to use (host|private)
                                       'host':    Run the container in the Docker host's cgroup namespace
                                       'private': Run the container in its own private cgroup namespace
                                       '':        Use the cgroup namespace as configured by the
                                                  default-cgroupns-mode option on the daemon (default)
      --cidfile string                 将容器ID写入文件 Write the container ID to the file
      --cpu-period int                 Limit CPU CFS (Completely Fair Scheduler) period
      --cpu-quota int                  Limit CPU CFS (Completely Fair Scheduler) quota
      --cpu-rt-period int              Limit CPU real-time period in microseconds
      --cpu-rt-runtime int             Limit CPU real-time runtime in microseconds
  -c, --cpu-shares int                 CPU shares (relative weight)
      --cpus decimal                   Number of CPUs
      --cpuset-cpus string             CPUs in which to allow execution (0-3, 0,1)
      --cpuset-mems string             MEMs in which to allow execution (0-3, 0,1)
  -d, --detach                         Run container in background and print container ID
      --detach-keys string             Override the key sequence for detaching a container
      --device list                    Add a host device to the container
      --device-cgroup-rule list        Add a rule to the cgroup allowed devices list
      --device-read-bps list           Limit read rate (bytes per second) from a device (default [])
      --device-read-iops list          Limit read rate (IO per second) from a device (default [])
      --device-write-bps list          Limit write rate (bytes per second) to a device (default [])
      --device-write-iops list         Limit write rate (IO per second) to a device (default [])
      --disable-content-trust          Skip image verification (default true)
      --dns list                       Set custom DNS servers
      --dns-option list                Set DNS options
      --dns-search list                Set custom DNS search domains
      --domainname string              Container NIS domain name
      --entrypoint string              Overwrite the default ENTRYPOINT of the image
  -e, --env list                       Set environment variables
      --env-file list                  Read in a file of environment variables
      --expose list                    Expose a port or a range of ports
      --gpus gpu-request               GPU devices to add to the container ('all' to pass all GPUs)
      --group-add list                 Add additional groups to join
      --health-cmd string              Command to run to check health
      --health-interval duration       Time between running the check (ms|s|m|h) (default 0s)
      --health-retries int             Consecutive failures needed to report unhealthy
      --health-start-period duration   Start period for the container to initialize before starting
                                       health-retries countdown (ms|s|m|h) (default 0s)
      --health-timeout duration        Maximum time to allow one check to run (ms|s|m|h) (default 0s)
      --help                           Print usage
  -h, --hostname string                Container host name
      --init                           Run an init inside the container that forwards signals and reaps
                                       processes
  -i, --interactive                    Keep STDIN open even if not attached
      --ip string                      IPv4 address (e.g., 172.30.100.104)
      --ip6 string                     IPv6 address (e.g., 2001:db8::33)
      --ipc string                     IPC mode to use
      --isolation string               Container isolation technology
      --kernel-memory bytes            Kernel memory limit
  -l, --label list                     Set meta data on a container
      --label-file list                Read in a line delimited file of labels
      --link list                      Add link to another container
      --link-local-ip list             Container IPv4/IPv6 link-local addresses
      --log-driver string              Logging driver for the container
      --log-opt list                   Log driver options
      --mac-address string             Container MAC address (e.g., 92:d0:c6:0a:29:33)
  -m, --memory bytes                   Memory limit
      --memory-reservation bytes       Memory soft limit
      --memory-swap bytes              Swap limit equal to memory plus swap: '-1' to enable unlimited swap
      --memory-swappiness int          Tune container memory swappiness (0 to 100) (default -1)
      --mount mount                    Attach a filesystem mount to the container
      --name string                    Assign a name to the container
      --network network                Connect a container to a network
      --network-alias list             Add network-scoped alias for the container
      --no-healthcheck                 Disable any container-specified HEALTHCHECK
      --oom-kill-disable               Disable OOM Killer
      --oom-score-adj int              Tune host's OOM preferences (-1000 to 1000)
      --pid string                     PID namespace to use
      --pids-limit int                 Tune container pids limit (set -1 for unlimited)
      --platform string                Set platform if server is multi-platform capable
      --privileged                     Give extended privileges to this container
  -p, --publish list                   Publish a container's port(s) to the host
  -P, --publish-all                    Publish all exposed ports to random ports
      --pull string                    Pull image before running ("always"|"missing"|"never") (default
                                       "missing")
      --read-only                      Mount the container's root filesystem as read only
      --restart string                 Restart policy to apply when a container exits (default "no")
      --rm                             Automatically remove the container when it exits
      --runtime string                 Runtime to use for this container
      --security-opt list              Security Options
      --shm-size bytes                 Size of /dev/shm
      --sig-proxy                      Proxy received signals to the process (default true)
      --stop-signal string             Signal to stop a container (default "SIGTERM")
      --stop-timeout int               Timeout (in seconds) to stop a container
      --storage-opt list               Storage driver options for the container
      --sysctl map                     Sysctl options (default map[])
      --tmpfs list                     Mount a tmpfs directory
  -t, --tty                            Allocate a pseudo-TTY
      --ulimit ulimit                  Ulimit options (default [])
  -u, --user string                    Username or UID (format: <name|uid>[:<group|gid>])
      --userns string                  User namespace to use
      --uts string                     UTS namespace to use
  -v, --volume list                    Bind mount a volume
      --volume-driver string           Optional volume driver for the container
      --volumes-from list              Mount volumes from the specified container(s)
  -w, --workdir string                 Working directory inside the container

 */
